#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <queue>
#include "thread.hpp"
#include "Log.hpp"
using namespace The_Thread;
using namespace log_ns;
static const int SIZE = 5;
// void test(){
//     while(true){
//         std::cout << "hello world" << std::endl;
//         sleep(1);
//     }
// }
template <class T>
class ThreadPool{
    private:
        void Lock(){
            pthread_mutex_lock(&_mutex);
        }
        void Unlock(){
            pthread_mutex_unlock(&_mutex);
        }
        void WakeUp(){
            pthread_cond_signal(&_cond);
        }
        void WakeUpAll(){
            pthread_cond_broadcast(&_cond);
        }
        void Sleep(){
            pthread_cond_wait(&_cond, &_mutex);
        }
        bool IsEmpty(){
            return _task_queue.empty();
        }
        void HandlerTask(const std::string& name){
            while(true)
            {
                Lock();
                while(IsEmpty() && _isrunning)
                {
                    _sleep_thread++;
                    Log(INFO, "%s thread sleep begin!\n", name.c_str());
                    Sleep();
                    Log(INFO, "%s thread wakeup!\n", name.c_str());
                    _sleep_thread--;
                }
                if(IsEmpty() && !_isrunning)
                {
                    Unlock();
                    break;
                }
                T t = _task_queue.front();
                _task_queue.pop();
                Unlock();
                t();
                //std::cout << name << ": " << t.result() << std::endl;
                //Log(INFO, "%s : %s\n", name.c_str(), t.result().c_str());
            }
         }
         ThreadPool(int num = SIZE)
        : _num(num)
        , _isrunning(false)
        , _sleep_thread(0)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);
        }
        void Init(){
            _isrunning = true;
            func_t fun = std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1);
            for(int i = 0;i < _num; i++)
            {
                std::string name = "Thread_" + std::to_string(i + 1);
                _threads.emplace_back(name, fun);
            }
        }
        void Strat(){
            for(auto& e : _threads)
            {
                usleep(10000);
                e.Start();
            }
        }
        ThreadPool(const ThreadPool &) = delete;
        void operator=(const ThreadPool &) = delete;
    public:
        
        void Stop(){
            Lock();
            _isrunning = false;
            WakeUpAll();
            Unlock();
        }
        void Equeue(const T& val){
            Lock();
            if(_isrunning)
            {
                _task_queue.push(val);
                if(_sleep_thread > 0)
                    WakeUp();
            }
            Unlock();
        }
        static ThreadPool<T>* GetInstanse(){
            if(_tp == nullptr)
            {
                LockGuard lockguard(&_sigmutex);
                if(_tp == nullptr)
                {
                    Log(INFO, "Creat threadpool\n");
                    _tp = new ThreadPool<T>();
                    _tp->Init();
                    _tp->Strat();
                }
                else
                {
                    Log(INFO, "Get threadpool\n");
                }
            }
            return _tp;
        }
        ~ThreadPool(){
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }
    private:
        int _num;
        std::vector<Thread> _threads;
        std::queue<T> _task_queue;
        bool _isrunning;
        pthread_mutex_t _mutex;
        pthread_cond_t _cond;
        int _sleep_thread;
        static ThreadPool<T>* _tp;
        static pthread_mutex_t _sigmutex;
};
template <class T>
    ThreadPool<T>* ThreadPool<T>::_tp = nullptr;
template <class T>
    pthread_mutex_t ThreadPool<T>::_sigmutex = PTHREAD_MUTEX_INITIALIZER;